package com.baidu.encrypt.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baidu.encrypt.common.utils.SM3Util;
import com.baidu.encrypt.common.utils.SM4Util;
import com.baidu.encrypt.entity.SampleInfo;
import com.baidu.encrypt.mapper.SampleInfoMapper;
import com.baidu.encrypt.service.SampleInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.StringJoiner;

@Service
public class SampleInfoServiceImpl extends ServiceImpl<SampleInfoMapper, SampleInfo> implements SampleInfoService {

    @Autowired
    private SM4Util sm4Util;

    @Override
    public <E extends IPage<SampleInfo>> E page(E page, Wrapper<SampleInfo> queryWrapper) {
        E result = super.page(page, queryWrapper);
        result.getRecords().forEach(this::decryptEntity); // 只解密，不做篡改校验
        return result;
    }


    @Override
    public boolean save(SampleInfo entity) {
        encryptEntity(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(SampleInfo entity) {
        encryptEntity(entity);
        return super.updateById(entity);
    }

    @Override
    public SampleInfo getById(Serializable id) {
        SampleInfo entity = super.getById(id);
        if (entity != null) {
            decryptEntity(entity);
            verifyIntegrity(entity);
        }
        return entity;
    }

    /** 加密（存库前） */
    private void encryptEntity(SampleInfo sample) {
        try {
            // 先用明文计算 SM3
            String sm3Plain = buildPlainString(sample);
            sample.setSm3(SM3Util.encrypt(sm3Plain));

            // 对每个字段加密（空值不加密，直接存 null）
            sample.setName(encryptNullable(sample.getName()));
            sample.setSource(encryptNullable(sample.getSource()));
            sample.setTags(encryptNullable(sample.getTags()));
            sample.setVersion(encryptNullable(sample.getVersion()));
            sample.setStoragePath(encryptNullable(sample.getStoragePath()));
            sample.setFileName(encryptNullable(sample.getFileName()));
            sample.setFileSize(encryptNullable(sample.getFileSize()));
            sample.setFileType(encryptNullable(sample.getFileType()));
            sample.setCreatedBy(encryptNullable(sample.getCreatedBy()));
            sample.setUpdatedBy(encryptNullable(sample.getUpdatedBy()));
            sample.setProjectId(encryptNullable(sample.getProjectId()));
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /** 解密（查库后） */
    private void decryptEntity(SampleInfo sample) {
        try {
            sample.setName(decryptNullable(sample.getName()));
            sample.setSource(decryptNullable(sample.getSource()));
            sample.setTags(decryptNullable(sample.getTags()));
            sample.setVersion(decryptNullable(sample.getVersion()));
            sample.setStoragePath(decryptNullable(sample.getStoragePath()));
            sample.setFileName(decryptNullable(sample.getFileName()));
            sample.setFileSize(decryptNullable(sample.getFileSize()));
            sample.setFileType(decryptNullable(sample.getFileType()));
            sample.setCreatedBy(decryptNullable(sample.getCreatedBy()));
            sample.setUpdatedBy(decryptNullable(sample.getUpdatedBy()));
            sample.setProjectId(decryptNullable(sample.getProjectId()));
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }

    /** 防篡改校验 */
    private void verifyIntegrity(SampleInfo sample) {
        String sm3New = SM3Util.encrypt(buildPlainString(sample));
        if (!sm3New.equals(sample.getSm3())) {
            throw new SecurityException("数据已被篡改！");
        }
    }

    /** 构建明文串（SM3用，null 统一转 ""） */
    private String buildPlainString(SampleInfo s) {
        return new StringJoiner("|")
                .add(nullToEmpty(s.getName()))
                .add(nullToEmpty(s.getSource()))
                .add(nullToEmpty(s.getTags()))
                .add(nullToEmpty(s.getVersion()))
                .add(nullToEmpty(s.getStoragePath()))
                .add(nullToEmpty(s.getFileName()))
                .add(nullToEmpty(s.getFileSize()))
                .add(nullToEmpty(s.getFileType()))
                .add(nullToEmpty(s.getCreatedBy()))
                .add(nullToEmpty(s.getUpdatedBy()))
                .add(nullToEmpty(s.getProjectId()))
                .toString();
    }

    /** 工具方法：null → "" */
    private String nullToEmpty(String str) {
        return str == null ? "" : str;
    }

    /** 工具方法：加密 null 安全 */
    private String encryptNullable(String value) throws Exception {
        return value == null ? null : sm4Util.encrypt(value);
    }

    /** 工具方法：解密 null 安全 */
    private String decryptNullable(String value) throws Exception {
        return value == null ? null : sm4Util.decrypt(value);
    }

}
